package com.ayou.executor;

import cn.hutool.core.util.ReflectUtil;
import com.ayou.annotations.Param;
import com.ayou.mapping.BoundSql;
import com.ayou.mapping.MappedStatement;
import com.ayou.parsing.GenericTokenParser;
import com.ayou.parsing.ParameterTokenHandler;
import com.ayou.session.Configuration;
import com.ayou.type.TypeHandler;
import lombok.SneakyThrows;

import java.lang.reflect.Field;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.ConnectException;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @description: 简单执行器
 * @author: ayouman
 * @date: 2024/7/1 23:09
 */
public class SimpleExecutor implements Executor{
    private Configuration configuration;

    public SimpleExecutor(Configuration configuration) {
        this.configuration = configuration;
    }

    @SneakyThrows
    @Override
    public <T> List<T> query(MappedStatement mappedStatement, Map<String, Object> parameterValues) {
        // 拿到连接
        Connection connection = getConnection();

        PreparedStatement preparedStatement = execute(mappedStatement, connection, parameterValues);

        List<T> results = handleResult(preparedStatement, mappedStatement);

        connection.close();

        return results;
    }

    @Override
    @SneakyThrows
    public int update(MappedStatement mappedStatement, Map<String, Object> parameterValues) {
        // 拿到连接
        Connection connection =getConnection();

        PreparedStatement preparedStatement = execute(mappedStatement, connection, parameterValues);
        // 拿到结果
        int updateCount = preparedStatement.getUpdateCount();

        connection.close();

        return updateCount;
    }

    @SneakyThrows
    private Connection getConnection() {
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/youbatis?useUnicode=true&characterEncoding=UTF8&useSSL=false&allowPublicKeyRetrieval=true", "root", "liadbiz");
        return connection;
    }

    @SneakyThrows
    private void setParams(PreparedStatement preparedStatement, List<String> parameterMappings, Map<String, Object> parameterValues) {
        Map<Class, TypeHandler> typeHandlerMap = configuration.getTypeHandlerMap();

        for (int i = 0; i < parameterMappings.size(); i++) {
            String jdbcColumnName = parameterMappings.get(i);
            if (jdbcColumnName.contains(".")) {
                String[] split = jdbcColumnName.split("\\.");
                String entityName = split[0];
                String fieldName = split[1];
                Object entity = parameterValues.get(entityName);
                Object fieldValue = ReflectUtil.getFieldValue(entity, fieldName);
                // TODO: 处理null情况
                typeHandlerMap.get(fieldValue.getClass()).setParameter(preparedStatement, i + 1, fieldValue);
            } else {
                Object columnValue = parameterValues.get(jdbcColumnName);
                typeHandlerMap.get(columnValue.getClass()).setParameter(preparedStatement, i + 1, columnValue);
            }
        }
    }

    @SneakyThrows
    private <T> List<T> handleResult(PreparedStatement preparedStatement, MappedStatement mappedStatement) {
        Map<Class, TypeHandler> typeHandlerMap = configuration.getTypeHandlerMap();

        // 拿到结果
        ResultSet resultSet = preparedStatement.getResultSet();

        // 拿到返回类型
        Class returnClass = mappedStatement.getResultType();

        // 循环遍历结果集
        List<String> columnNames = new ArrayList<>();
        ResultSetMetaData metaData = resultSet.getMetaData();
        int columnCount = metaData.getColumnCount();
        for (int i = 0; i < columnCount; i++) {
            columnNames.add(metaData.getColumnName(i + 1));
        }

        List list = new ArrayList();
        while (resultSet.next()){
            // 设置结果
            Object object = returnClass.newInstance();
            for (int i = 0; i < columnNames.size(); i++) {
                String columnName = columnNames.get(i);
                Field field = ReflectUtil.getField(returnClass, columnName);
                Object val = typeHandlerMap.get(field.getType()).getResult(resultSet, columnName);
                ReflectUtil.setFieldValue(object, columnName, val);
            }
            list.add(object);
        }
        // 关闭资源 可省？
        resultSet.close();
        preparedStatement.close();
        return list;
    }

    @SneakyThrows
    private PreparedStatement execute(MappedStatement mappedStatement, Connection connection, Map<String, Object> parameterValues) {
        // 解析sql
        BoundSql boundSql = mappedStatement.getBoundSql();
        System.out.println("sql:" + boundSql.getSql());
        // 设置值
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSql());

        setParams(preparedStatement, boundSql.getParameterMappings(), parameterValues);

        preparedStatement.execute();
        return preparedStatement;
    }
}
